from flask import Flask, render_template, jsonify, Response, request
import os
import json
import requests
from PIL import Image
import io
import base64
from urllib.parse import urljoin, urlparse
import threading

app = Flask(__name__, static_folder='static', template_folder='templates')

# 加载配置文件
def load_config():
    try:
        with open('config.json', 'r', encoding='utf-8') as f:
            config = json.load(f)
            # 处理 ~ 路径
            if "image_directories" in config:
                config["image_directories"] = [os.path.expanduser(path) for path in config["image_directories"]]
            return config
    except FileNotFoundError:
        # 默认配置
        return {
            "image_directories": ["."],
            "remote_servers": [],
            "supported_formats": [".jpg", ".jpeg", ".webp"],
            "thumbnail_size": [300, 300],
            "preload_count": 10,
            "lazy_load": True
        }

CONFIG = load_config()
SUPPORTED_FORMATS = tuple(CONFIG.get("supported_formats", [".jpg", ".png", ".webp"]))

def get_local_image_files(folder=None):
    """获取本地配置目录下的所有图像文件，可选择性地筛选特定文件夹"""
    image_files = []
    directories = CONFIG.get("image_directories", ["."])

    for directory in directories:
        if os.path.exists(directory):
            for root, dirs, files in os.walk(directory):
                # 如果指定了文件夹，只处理该文件夹下的文件
                if folder:
                    # 获取当前目录相对于根目录的路径
                    relative_root = os.path.relpath(root, directory)
                    if relative_root == ".":
                        relative_root = "/"
                    else:
                        # 只取直接子目录
                        relative_root = relative_root.split(os.sep)[0]

                    # 如果当前目录不匹配指定文件夹，则跳过
                    if relative_root != folder:
                        continue
                else:
                    # 如果没有指定文件夹（默认情况），只处理根目录下的文件
                    relative_root = os.path.relpath(root, directory)
                    if relative_root != ".":
                        continue

                for file in files:
                    if file.lower().endswith(SUPPORTED_FORMATS):
                        # 获取相对路径
                        relative_path = os.path.relpath(os.path.join(root, file), ".")
                        image_files.append({
                            'name': file,
                            'path': relative_path,
                            'full_path': os.path.join(root, file),
                            'type': 'local'
                        })
    return image_files

def get_remote_image_files():
    """获取远程服务器上的图像文件"""
    image_files = []
    remote_servers = CONFIG.get("remote_servers", [])

    for server in remote_servers:
        try:
            # 获取远程服务器上的文件列表
            response = requests.get(urljoin(server, "api/images"), timeout=5)
            if response.status_code == 200:
                remote_images = response.json()
                for img in remote_images:
                    # 添加服务器信息
                    img['server'] = server
                    img['type'] = 'remote'
                    image_files.append(img)
        except Exception as e:
            print(f"获取远程服务器 {server} 图像列表失败: {e}")
            # 即使某个服务器连接失败，也不应该中断整个过程
            pass

    return image_files

def get_image_files():
    """获取所有图像文件（本地和远程）"""
    local_images = get_local_image_files()
    remote_images = get_remote_image_files()
    return local_images + remote_images

def get_image_folders():
    """获取包含图像文件的文件夹列表"""
    folders = set()
    directories = CONFIG.get("image_directories", ["."])

    for directory in directories:
        if os.path.exists(directory):
            for root, dirs, files in os.walk(directory):
                for file in files:
                    if file.lower().endswith(SUPPORTED_FORMATS):
                        # 获取文件夹路径
                        folder_path = os.path.relpath(root, directory)
                        if folder_path == ".":
                            folder_path = "/"
                        else:
                            # 只取直接子目录
                            folder_path = folder_path.split(os.sep)[0]
                        folders.add(folder_path)
                        break  # 找到一个图像文件就足够了
    return sorted(list(folders))

@app.route('/')
def index():
    """主页路由"""
    return render_template('index.html')

@app.route('/api/images')
def get_images():
    """API接口：获取所有图像文件信息，支持按文件夹筛选"""
    # 获取查询参数中的文件夹名称
    folder = request.args.get('folder')

    # 获取本地图像文件（支持文件夹筛选）
    local_images = get_local_image_files(folder)

    # 获取远程图像文件（暂不支持文件夹筛选）
    remote_images = get_remote_image_files()

    # 如果指定了文件夹，只返回本地图像
    if folder:
        return jsonify(local_images)
    else:
        return jsonify(local_images + remote_images)

@app.route('/api/folders')
def get_folders():
    """API接口：获取包含图像文件的文件夹列表"""
    folders = get_image_folders()
    return jsonify(folders)

@app.route('/api/image/<path:image_path>')
def get_image(image_path):
    """API接口：获取单个图像数据"""
    try:
        # URL解码
        import urllib.parse
        image_path = urllib.parse.unquote(image_path)

        # 检查是否为远程图像请求（通过查询参数）
        server = request.args.get('server')
        if server:
            # 远程图像请求
            remote_url = urljoin(server, image_path)
            response = requests.get(remote_url, timeout=10)
            if response.status_code == 200:
                # 确定MIME类型
                if image_path.lower().endswith('.webp'):
                    mime_type = 'image/webp'
                else:
                    mime_type = 'image/jpeg'
                return Response(response.content, mimetype=mime_type)
            else:
                return "Remote image not found", 404

        # 本地图像请求
        # 安全检查：确保路径在配置的图像目录内
        abs_requested_path = os.path.abspath(image_path)

        # 检查请求的路径是否在配置的图像目录中
        allowed = False
        directories = CONFIG.get("image_directories", ["."])

        for directory in directories:
            abs_directory = os.path.abspath(directory)
            # 确保请求的文件在允许的目录内
            if abs_requested_path.startswith(abs_directory) and os.path.commonpath([abs_directory, abs_requested_path]) == abs_directory:
                allowed = True
                break

        if not allowed:
            return "Access denied", 403

        # 检查文件是否存在
        if not os.path.exists(image_path):
            return "File not found", 404

        with open(image_path, 'rb') as f:
            image_data = f.read()

        # 确定MIME类型
        if image_path.lower().endswith('.webp'):
            mime_type = 'image/webp'
        else:
            mime_type = 'image/jpeg'

        return Response(image_data, mimetype=mime_type)
    except Exception as e:
        return str(e), 404

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=3333)
